package com.zz.framework.core.utils.sandbox

import android.graphics.Bitmap
import android.net.Uri
import android.os.Environment
import com.zz.framework.core.utils.AppGlobals
import com.zz.framework.core.utils.file.sandbox.DirectoryType
import com.zz.framework.core.utils.file.sandbox.FileType
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.IOException
import java.io.InputStream

/**
 * Copyright © 2024 zhun All rights reserved.
 * Created by Zha0Zhun on 2024/6/22 09:24.
 * @author: Zha0Zhun 1820022519@qq.com
 * @version: V1.0
 */
internal class FileLegacyImpl:IFile {
    companion object {
        val context = AppGlobals.getApplication()
        private val mInstance by lazy { FileLegacyImpl() }
        fun getInstance(): IFile {
            return mInstance
        }
    }
    override fun newFile(displayName: String, content: ByteArray, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        val fileType = FileType.fromFileName(displayName)
        val directory = File(Environment.getExternalStoragePublicDirectory(fileType.directory), displayName)
        try {
            if (!directory.parentFile.exists()) {
                directory.parentFile.mkdirs()
            }
            FileOutputStream(directory).use { outputStream ->
                outputStream.write(content)
            }
            onSuccess(Uri.fromFile(directory))
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun newFile(displayName: String, inputStream: InputStream, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        val fileType = FileType.fromFileName(displayName)
        val directory = File(Environment.getExternalStoragePublicDirectory(fileType.directory), displayName)
        try {
            if (!directory.parentFile.exists()) {
                directory.parentFile.mkdirs()
            }
            FileOutputStream(directory).use { outputStream ->
                inputStream.copyTo(outputStream)
            }
            onSuccess(Uri.fromFile(directory))
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun deleteFile(uri: Uri, onSuccess: () -> Unit, onError: (Exception) -> Unit) {
        try {
            val file = File(uri.path ?: "")
            if (file.exists() && file.delete()) {
                onSuccess()
            } else {
                onError(IOException("Failed to delete file."))
            }
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun deleteFile(displayName: String, onSuccess: () -> Unit, onError: (Exception) -> Unit) {
        val fileType = FileType.fromFileName(displayName)
        val directory = Environment.getExternalStoragePublicDirectory(fileType.directory)
        val file = File(directory, displayName)
        try {
            if (file.exists() && file.delete()) {
                onSuccess()
            } else {
                onError(IOException("Failed to delete file."))
            }
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun readFile(uri: Uri, onSuccess: (ByteArray) -> Unit, onError: (Exception) -> Unit) {
        try {
            context.contentResolver.openInputStream(uri)?.use { inputStream ->
                val byteArray = inputStream.readBytes()
                onSuccess(byteArray)
            } ?: onError(IOException("Failed to open input stream."))
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun readFile(displayName: String, onSuccess: (ByteArray) -> Unit, onError: (Exception) -> Unit) {
        val fileType = FileType.fromFileName(displayName)
        val directory = Environment.getExternalStoragePublicDirectory(fileType.directory)
        val file = File(directory, displayName)
        if (file.exists()) {
            try {
                FileInputStream(file).use { inputStream ->
                    val byteArray = inputStream.readBytes()
                    onSuccess(byteArray)
                }
            } catch (e: Exception) {
                onError(e)
            }
        } else {
            onError(IOException("File not found."))
        }
    }

    override fun queryFileByName(displayName: String, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        val fileType = FileType.fromFileName(displayName)
        val directory = Environment.getExternalStoragePublicDirectory(fileType.directory)
        val file = File(directory, displayName)
        if (file.exists()) {
            onSuccess(Uri.fromFile(file))
        }else{
            onError(IOException("File not found."))
        }
    }

    override fun updateFile(uri: Uri, newContent: ByteArray, onSuccess: () -> Unit, onError: (Exception) -> Unit) {
        try {
            context.contentResolver.openOutputStream(uri)?.use { outputStream ->
                outputStream.write(newContent)
                onSuccess()
            } ?: onError(IOException("Failed to open output stream."))
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun updateFile(displayName: String, newContent: ByteArray, onSuccess: () -> Unit, onError: (Exception) -> Unit) {
        queryFileByName(displayName, { uri ->
            updateFile(uri, newContent, onSuccess, onError)
        }, onError)
    }

    override fun renameFile(uri: Uri, newDisplayName: String, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        val file = File(uri.path ?: run {
            onError(IOException("Invalid URI"))
            return
        })
        val newFile = File(file.parent, newDisplayName)
        try {
            if (file.exists() && file.renameTo(newFile)) {
                onSuccess(Uri.fromFile(newFile))
            } else {
                onError(IOException("Failed to rename file."))
            }
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun renameFile(displayName: String, newDisplayName: String, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        queryFileByName(displayName, { uri ->
            renameFile(uri, newDisplayName, onSuccess, onError)
        }, onError)
    }

    override fun writeInputStreamToAlbum(inputStream: InputStream, displayName: String, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        newFile(displayName, inputStream, onSuccess, onError)
    }

    override fun addBitmapToAlbum(displayName: String, bitmap: Bitmap, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        val outputStream = ByteArrayOutputStream()
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream)
        val inputStream = outputStream.toByteArray().inputStream()
        newFile(displayName, inputStream, onSuccess, onError)
    }

    override fun mkdirs(displayName: String, directoryType: DirectoryType, onSuccess: (Uri) -> Unit, onError: (Exception) -> Unit) {
        try {
            val directory = Environment.getExternalStoragePublicDirectory(directoryType.directory)
            val file = File(directory, displayName)
            if (!file.exists()) {
                if (file.mkdirs()) {
                    onSuccess(Uri.fromFile(file))
                } else {
                    onError(IOException("Failed to create directory ${file.absolutePath}"))
                }
            } else {
                onSuccess(Uri.fromFile(file))
            }
        } catch (e: Exception) {
            onError(e)
        }
    }

    override fun getFileName(uri: Uri): String? {
        val file = File(uri.path ?: run {
            return null
        })
        return file?.name
    }
}